﻿using Xejen.Ipc.Framework.Controllers;
using Xejen.Ipc.Framework.Steps;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Xejen.Ipc.Framework.Flows
{
    /// <inheritdoc cref="IFlow{TData}"/>
    /// <creator>marc</creator>
    public class Flow<TData> : IFlow<TData>
        where TData : new()
    {
        private static int _flowCount = 0;
        private readonly FlowInstance<TData> _flowInstance;
        private readonly FlowExecutionContext<TData> _context;

        private CancellationToken _cancellationToken;

        /// <inheritdoc/>
        public int Id { get; set; }
        /// <inheritdoc/>
        public string Name { get; set; }
        /// <inheritdoc/>
        public IFlow<TData> Parent { get; set; }
        /// <inheritdoc/>
        public TData Data { get; }
        /// <inheritdoc/>
        public FlowStatus Status { get; set; }
        /// <inheritdoc/>
        public ILogger Logger { get; set; }
        /// <inheritdoc/>
        public CancellationToken CancellationToken => _cancellationToken;

        private IReadOnlyList<IController<TData>> _controllers;
        /// <inheritdoc/>
        public IReadOnlyList<IController<TData>> Controllers
        {
            get
            {
                return _controllers;
            }
            set
            {
                foreach (IController<TData> controller in value)
                {
                    controller.Error += (sender, args) =>
                    {
                        OnError(this, args);
                    };
                }
                _controllers = value;
            }
        }

        /// <inheritdoc/>
        public event EventHandler<FlowEventArgs<TData>> Started;
        /// <inheritdoc/>
        public event EventHandler<FlowEventArgs<TData>> Paused;
        /// <inheritdoc/>
        public event EventHandler<FlowEventArgs<TData>> Resumed;
        /// <inheritdoc/>
        public event EventHandler<FlowEventArgs<TData>> Stopped;
        /// <inheritdoc/>
        public event EventHandler<ErrorEventArgs<TData>> Error;
        /// <inheritdoc/>
        public event EventHandler<FlowEventArgs<TData>> CycleCompleted;
        /// <inheritdoc/>
        public event EventHandler<ScanIntervalExceededEventArgs<TData>> ScanIntervalExceeded;

        /// <inheritdoc cref="Flow{TData}"/>
        public Flow(string name)
        {
            _flowCount++;
            Id = _flowCount;
            Name = name;
            _flowInstance = new FlowInstance<TData>(this);

            FlowExecutionContext<TData> context = new FlowExecutionContext<TData>();
            context.Flow = this;
            Data = context.Data;
            Logger = HostRuntime.LoggerManager.CreateLogger<IFlow<TData>>();
            _context = context;

        }

        /// <inheritdoc cref="Flow{TData}"/>
        public Flow(string name, IFlow<TData> parent)
        {
            Check.NotNull(parent, nameof(parent));

            _flowCount++;
            Id = _flowCount;
            Name = name;
            _flowInstance = new FlowInstance<TData>(this, parent);

            FlowExecutionContext<TData> context = new FlowExecutionContext<TData>(parent.Data);
            context.Flow = this;
            Data = parent.Data;
            Parent = parent;
            Logger = parent.Logger;
            _context = context;
        }

        /// <inheritdoc/>
        public void Start(CancellationToken cancellationToken = default)
        {
            Start(HostRuntime.IpcHostOptions.LoopCount, cancellationToken);
        }

        /// <inheritdoc/>
        public void Start(int loopCount, CancellationToken cancellationToken = default)
        {
            if (loopCount == 0)
            {
                return;
            }

            lock (typeof(object))
            {
                if (Status == FlowStatus.Running || Status == FlowStatus.Paused)
                {
                    return;
                }
                Status = FlowStatus.Running;
            }

            if (cancellationToken == default)
            {
                _cancellationToken = this.Parent.CancellationToken;
            }
            else
            {
                _cancellationToken = cancellationToken;
            }

            OnStarted(this, new FlowEventArgs<TData>(_flowInstance));

            Task.Factory.StartNew(async () =>
            {
                Thread.CurrentThread.Priority = ThreadPriority.Lowest;

                Stopwatch stopwatch = new Stopwatch();

                IReadOnlyList<IController<TData>> controllers = this.Controllers;
                if (controllers == null || controllers.Count == 0)
                {
                    await Task.CompletedTask;
                    return;
                }

                int i = 0;
                while (loopCount < 0 || i < loopCount)
                {
                    if (loopCount > 0)
                    {
                        i++;
                    }

                    _flowInstance.CycleEndTime = null;
                    _flowInstance.CycleExecutionTime = null;

                    if (cancellationToken.IsCancellationRequested)
                    {
                        Debug.WriteLine($"流程内的当前流程状态被取消，流程停止并返回");
                        break;
                    }
                    if (Status == FlowStatus.Stopped)
                    {
                        Debug.WriteLine($"流程内的当前流程状态变更为：{_context.Flow.Status}，流程停止并返回");
                        break;
                    }

                    if (Status == FlowStatus.Paused)
                    {
                        await Task.Delay(10);
                        continue;
                    }

                    _flowInstance.CycleStartTime = StandardTime.Now;
                    stopwatch.Restart();

                    await controllers.First().RunAsync(_context, cancellationToken);

                    stopwatch.Stop();
                    _flowInstance.CycleEndTime = StandardTime.Now;
                    TimeSpan elapsed = stopwatch.Elapsed;
                    _flowInstance.CycleExecutionTime = elapsed;

                    if (HostRuntime.IpcHostOptions.ScanIntervalThreshold > 0)
                    {
                        if (elapsed.TotalMilliseconds > HostRuntime.IpcHostOptions.ScanIntervalThreshold)
                        {
                            this.OnScanIntervalExceeded(this, new ScanIntervalExceededEventArgs<TData>(_flowInstance, elapsed));
                        }
                    }

                    OnCompleted(this, new FlowEventArgs<TData>(_flowInstance));

                    await Task.Delay(1);
                }

                Status = FlowStatus.Stopped;
            }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            //Thread thread = new Thread(() =>
            //{
            //    // 设置线程为后台线程，从而确保不受 UI 线程的影响
            //    Thread.CurrentThread.IsBackground = true;


            //});

            //thread.Priority = ThreadPriority.Highest;
            //thread.Start();
        }

        /// <inheritdoc/>
        public void Pause()
        {
            if (Status == FlowStatus.Stopped)
            {
                return;
            }
            if (!(Status == FlowStatus.Running))
            {
                return;
            }

            Status = FlowStatus.Paused;
            OnPaused(this, new FlowEventArgs<TData>(_flowInstance));
        }
        /// <inheritdoc/>
        public void Resume()
        {
            if (Status == FlowStatus.Stopped)
            {
                return;
            }
            if (!(Status == FlowStatus.Paused))
            {
                return;
            }

            Status = FlowStatus.Running;
            OnResumed(this, new FlowEventArgs<TData>(_flowInstance));
        }
        /// <inheritdoc/>
        public void Stop()
        {
            if (Status == FlowStatus.Stopped)
            {
                return;
            }

            Status = FlowStatus.Stopped;
            OnStopped(this, new FlowEventArgs<TData>(_flowInstance));
        }

        /// <summary>
        /// 当启动时触发
        /// </summary>
        protected virtual void OnStarted(object sender, FlowEventArgs<TData> args)
        {
            Started?.Invoke(this, args);
        }
        /// <summary>
        /// 当暂停时触发
        /// </summary>
        protected virtual void OnPaused(object sender, FlowEventArgs<TData> args)
        {
            Paused?.Invoke(this, args);
        }
        /// <summary>
        /// 当恢复时触发
        /// </summary>
        protected virtual void OnResumed(object sender, FlowEventArgs<TData> args)
        {
            Resumed?.Invoke(this, args);
        }
        /// <summary>
        /// 当停止时触发
        /// </summary>
        protected virtual void OnStopped(object sender, FlowEventArgs<TData> args)
        {
            Stopped?.Invoke(this, args);
        }
        /// <summary>
        /// 当发生错误时触发
        /// </summary>
        protected virtual void OnError(object sender, ErrorEventArgs<TData> args)
        {
            Error?.Invoke(sender, args);
        }
        /// <summary>
        /// 当一轮周期循环结束时触发
        /// </summary>
        protected virtual void OnCompleted(object sender, FlowEventArgs<TData> args)
        {
            CycleCompleted?.Invoke(sender, args);
        }
        /// <summary>
        /// 当扫描周期大于设定值时触发
        /// </summary>
        protected virtual void OnScanIntervalExceeded(object sender, ScanIntervalExceededEventArgs<TData> args)
        {
            ScanIntervalExceeded?.Invoke(sender, args);
        }
    }
}
